package com.kfm.main;

import com.kfm.dao.IUserinfoDao;
import org.apache.ibatis.io.Resources;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyMyBatis {

    public static void main(String[] args) throws Exception {
        // mybatis 的配置文件位置
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);

        Configuration config = new Configuration();
        // DOM 4j 解析 xml 配置文件

        SAXReader reader = new SAXReader();
        Document read = reader.read(inputStream);
        Element root = read.getRootElement();

        List<Element> propertyElements = root.selectNodes("//property");

        for (Element element : propertyElements){
            String name = element.getName();
            if("driver".equals(name)){
                //表示驱动
                //获取 property 标签 value 属性的值
                String driver = element.attributeValue("value");
                config.setDriver(driver);
            }
            if("url".equals(name)){
                //表示连接字符串
                //获取 property 标签 value 属性的值
                String url = element.attributeValue("value");
                config.setUrl(url);
            }
            if("username".equals(name)){
                //表示用户名
                //获取 property 标签 value 属性的值
                String username = element.attributeValue("value");
                config.setUsername(username);
            }
            if("password".equals(name)){
                //表示密码
                //获取 property 标签 value 属性的值
                String password = element.attributeValue("value");
                config.setPassword(password);
            }
        }

        //取出 mappers 中的所有 mapper 标签，判断他们使用了 resource 还是 class 属性
        List<Element> mapperElements = root.selectNodes("//mappers/mapper");

        for (Element mapperElement : mapperElements){
            Attribute attribute = mapperElement.attribute("resource");
            if (attribute != null){
                //取出属性的值
                String mapperPath = attribute.getValue();// 获 取 属 性 的 值"com/itlaobing/dao/IUserInfoDao.xml"
                //把映射配置文件的内容获取出来，封装成一个 map
                Map<String, Mapper> mappers = loadMapperConfiguration(mapperPath);
                //给 configuration 中的 mappers 赋值
                config.setMappers(mappers);
            } else {
                Attribute aClass = mapperElement.attribute("class");
                Map<String, Mapper> mappers = loadMapperAnnotation(aClass.getValue());
                config.setMappers(mappers);
            }
        }

        Class<IUserinfoDao> iUserinfoDaoClass = IUserinfoDao.class;

        System.out.println(iUserinfoDaoClass.getName());

//        .selectAll

        System.out.println(config.getMappers().get(iUserinfoDaoClass.getName() + ".selectAll"));




    }

    private static Map<String,Mapper> loadMapperConfiguration(String mapperPath)throws Exception {
        Map<String, Mapper> mappers = new HashMap<>();

        InputStream resourceAsStream = MyMyBatis.class.getClassLoader().getResourceAsStream(mapperPath);

        SAXReader reader = new SAXReader();
        Document read = reader.read(resourceAsStream);

        Element rootElement = read.getRootElement();

        //4.获取根节点的 namespace 属性取值
        String namespace = rootElement.attributeValue("namespace");//是组成 map 中 key 的 部分


        List<Element> list = rootElement.selectNodes("//select");

        for(Element selectElement : list){
            //取出 id 属性的值 组成 map 中 key 的部分
            String id = selectElement.attributeValue("id");
            //取出 resultType 属性的值 组成 map 中 value 的部分
            String resultType = selectElement.attributeValue("resultType");
            //取出文本内容 组成 map 中 value 的部分
            String queryString = selectElement.getText();
            //创建 Key
            String key = namespace+"."+id;
            //创建 Value
            Mapper mapper = new Mapper();
            mapper.setSql(queryString);
            mapper.setResultType(resultType);
            //把 key 和 value 存入 mappers 中
            mappers.put(key,mapper);
        }
        return mappers;
    }

    public static Map<String, Mapper> loadMapperAnnotation(String daoClassPath){

        Map<String,Mapper> mappers = new HashMap<>();
        try {
            Class<?> aClass = Class.forName(daoClassPath);

            Method[] declaredMethods = aClass.getDeclaredMethods();

            for(Method method : declaredMethods){
                Mapper mapper = new Mapper();
                MySelect annotation = method.getAnnotation(MySelect.class);
                String name = method.getName();

                String sql = annotation.value();
                mapper.setSql(sql);
                Type genericReturnType = method.getGenericReturnType();

                if(genericReturnType instanceof ParameterizedType){
                    Type[] actuallyTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments();
                    for (Type actuallyTypeArgument : actuallyTypeArguments) {
                        String typeName = actuallyTypeArgument.getTypeName();
                        mapper.setResultType(typeName);
                    }
                }

                mappers.put(daoClassPath + "." + name, mapper);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return mappers;
    }
}
